#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "yyfunction.h"
#include "variables.h"

struct symbol_table * _table_ = NULL;

struct symbol_table * getStackTable(){
	printf("entering getStackTable");
	if(_table_ == NULL)
		_table_ = symbol_table_allocate(NULL);
	return _table_;
}
/*
 Gestion de la table des symboles :
 allocation
 pop >> depile la table et la libere retournant la precedente
 
 push >> empile une table sur une autre et la retourne
 */

struct symbol_table * symbol_table_allocate(struct symbol_table * parent){
	printf("entering symbol_table_allocate\n");
	struct symbol_table * n =  malloc(sizeof(struct symbol_table));
	n->count = 0;
	n->parent = parent;
	n->symbols = NULL;
	if(parent != NULL)
		n->id = parent->id+1;
	else
		n->id=1;
	n->MAX = 0;
	return n;
}

struct symbol_table * symbol_table_pop(struct symbol_table * actuel){
	printf("entering symbol_table_pop\n");
	struct symbol_table * prec = actuel->parent;
	int i=0;
	for(;i<actuel->count; i++){
		free(actuel->symbols[i].name_var);
	}
	free(actuel->symbols);
	free(actuel);
	
	return prec;
}

struct symbol_table * symbol_table_push(struct symbol_table * actuel){
	printf("entering symbol_table_push\n");
	return symbol_table_allocate(actuel);
}

void symbol_filter_pointvirgule(char * a){
	printf("entering symbol_filter_pointvirgule\n");
	strtok(a,";");
}

int symbol_find_type(char * s){
	printf("entering symbol_find_type\n");
	if(strncmp(s,"int ",4) == 0){
		return TYPE_INT;
	}else if(strncmp(s,"float ",4) == 0){
		return TYPE_FLOAT;
	}
	else return -1; // on ne sait toujours pas ce que c'est...
}

struct symbol * symbol_find_var(struct symbol_table * entries, char *s){
	printf("entering symbol_find_var\n");
	struct symbol_table * actuel = entries;
	int i;
	while(entries != NULL){
		for(i=0;i<entries->count;i++){
			if(strcmp(s,entries->symbols[i].name_var) == 0)
				return &(entries->symbols[i]);
		}
		//parcourt la mere
		entries = entries->parent;
	}
	
	return NULL;
}

/**
 * return 0 if the two var have the same type
 */
int symbol_compare_type(struct symbol_table * table, char * entered_a, char * entered_b){
	printf("entering symbol_compare_type\n");
	char * a = malloc((strlen(entered_a)+1)*sizeof(char));
	strcpy(a, entered_a);
	char * b = malloc((strlen(entered_b)+1)*sizeof(char));
	strcpy(b, entered_b);
	int same_type = 1;

	symbol_filter_pointvirgule(a);
	symbol_filter_pointvirgule(b);

	struct symbol * s_a = symbol_find_var(table, a);
	struct symbol * s_b = symbol_find_var(table, b);
	
	if(s_a == NULL || s_b == NULL){
		int type_a = -42;
		int type_b = -314159;
		type_a = (s_a == NULL) ? symbol_find_type(a) : s_a->type_var;
		type_b = (s_b == NULL) ? symbol_find_type(b) : s_b->type_var;
		
		if (type_a == type_b) same_type = 0;
	}else if(s_a->type_var == s_b->type_var){
		same_type = 0;
	}
	free(a);
	free(b);

	return same_type;
}

char * symbol_get_temp_type(struct symbol_table * table, char * entered_a){
	printf("entering symbol_get_temp_type\n");
	char * a = malloc((strlen(entered_a)+1)*sizeof(char));
	strcpy(a, entered_a);
	symbol_filter_pointvirgule(a);
	struct symbol * s_a = symbol_find_var(table, entered_a);
	free(a);
	
	if(s_a == NULL)
		return "void";
	
	int c = 2*s_a->number_array; //on alloue []
	if(s_a->type_var == TYPE_INT)
		c+= 3;
	else if(s_a->type_var  == TYPE_FLOAT)
 		c+= 5;
	else if(s_a->type_var  == TYPE_VOID)
 		c+= 4;
	c++; // \O
	c*=sizeof(char);
	char * toreturn = malloc(c);
	char * modif = toreturn;
	if(s_a->type_var == TYPE_INT){
		sprintf(toreturn,"int");
		modif+=3;
	}else if(s_a->type_var == TYPE_FLOAT){
		sprintf(toreturn,"float");
		modif+=5;
	}else if(s_a->type_var == TYPE_VOID){
		sprintf(toreturn,"void");
		modif+=4;
	}	
	int i=0;
	for(i=0;i< s_a->number_array;i++){
		modif[0]='[';
		modif[1]='[';
		modif+=2;
	}
	modif[0]='\0'; // on termine la chaine

	return toreturn;
}

struct symbol * get_current(struct symbol_table * table){
	printf("entering get_current\n");
	return &(table->symbols[table->count-1]);
}

struct symbol * stack_symbol(struct symbol_table * table){
	printf("entering stack_symbol\n");
	if(table->MAX == table->count){
		int taille_max = (table->MAX+1)*2;
		struct symbol * n = malloc(taille_max);
		memcpy(n, table->symbols, sizeof(*(table->symbols)) * table->count);
		free(table->symbols);
		table->symbols = n;
		table->MAX = taille_max;
	}
	
	table->count++;
	struct symbol * s = &(table->symbols[table->count-1]);
	s->number_array = 0;
	s->name_var = "-";
	s->type_var = table->tmp_type;
	return s;
}

void print(struct symbol_table * table){
	printf("entering print\n");
	if(table == NULL){
		return;
	}else{
		int i;
		if(table->parent != NULL){
			print(table->parent);
		}
		printf("\n\nTABLE DES SYMBOLES %d\n", table->id);
		struct symbol * s;
		for (i = 0; i < table->count; i++){
			s = &(table->symbols[i]);
			printf("name_var : %s , type : %d, [] : %d\n", s->name_var, s->type_var, s->number_array);
		}
	}
}